package com.lz.config.filter;

import java.util.*;
import java.util.stream.*;
import com.google.gson.Gson;
import com.lz.common.anno.AnonymousAccess;
import com.lz.config.common.security.domain.MyUserDetails;
import com.lz.config.common.utils.JwtUtil;
import com.lz.config.common.utils.SpringUtil;
import com.lz.config.dal.entity.User;
import com.lz.config.handlerInterceptor.LogInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration

public class LzOncePerRequestFilter extends OncePerRequestFilter {

    private static final Logger log = LoggerFactory.getLogger(LogInterceptor.class);

    //我要把这个类出现的魔法值写在这
    private static final String TOKEN = "TOKEN";
    //dev
    private static final String DEV = "dev";
    //  虚拟身份名称
    private static final String ANONYMOUS_IDENTITY = "virtualIdentity";
    //虚拟ID
    private static final String ANONYMOUS_ID = "1113";


    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private Gson gson;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        log.info("进入自定义过滤器,获取==>{}", "匿名访问方法");
        if (request.getRequestURI().contains("api/user/add")||request.getRequestURI().contains("api/user/login")) {
            filterChain.doFilter(request, response);
            return;
        }
        String requestURI = request.getRequestURI();
        List<String> anonymousAccessUrls = getAnonymousAccessUrls();
        if (anonymousAccessUrls.contains(requestURI)) {
            MyUserDetails myUserDetails = new MyUserDetails();
            User user = new User();
            user.setUsername(ANONYMOUS_IDENTITY);
            user.setId(ANONYMOUS_ID);
            myUserDetails.setUser(user);
            UsernamePasswordAuthenticationToken UserDetailsAuthenticationToken = new UsernamePasswordAuthenticationToken(myUserDetails, null, myUserDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(UserDetailsAuthenticationToken);
            filterChain.doFilter(request, response);
            return;
        }

        String token = request.getHeader(TOKEN);
        if (token == null || token.trim().isEmpty()) {
            // 请求头没有token
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            filterChain.doFilter(request, response);
            return;
        }//鎵弿鍒扮
        String userid = JwtUtil.getUsernameFromToken(token);
        if (userid == null) {
            // 过期或者无效的token
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            filterChain.doFilter(request, response);
            return;
        }
        String obj = redisTemplate.opsForValue().get("login:" + userid);


        if (obj == null) {
            // 缓存中没有信息
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            filterChain.doFilter(request, response);
            return;
        }

        MyUserDetails redisInfo = gson.fromJson(obj, MyUserDetails.class);

        //todo 第三个参数是权限信息
        UsernamePasswordAuthenticationToken UserDetailsAuthenticationToken = new UsernamePasswordAuthenticationToken(redisInfo, null, redisInfo.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(UserDetailsAuthenticationToken);
        filterChain.doFilter(request, response);
        log.info("退出自定义过滤器,获取==>{}", "匿名访问方法");
    }

    /**
     * 仅在开发环境（dev）下生效，非开发环境将返回空列表。
     *
     * @return 标记为匿名访问的URL列表，如果不是开发环境则返回空列表。
     */
    private List<String> getAnonymousAccessUrls() {
//仅仅在dev开发环境开启这个方法
//        String activeProfile = SpringUtil.getActiveProfile();
//        if (!activeProfile.equals(DEV)) {
//            return Collections.emptyList();
//        }

        RequestMappingHandlerMapping mapping = SpringUtil.getBean(RequestMappingHandlerMapping.class);
        Map<RequestMappingInfo, HandlerMethod> handlerMethods =
                mapping.getHandlerMethods();

        return handlerMethods.entrySet().stream()
                .filter(entry -> {
                    // 检查方法上是否有@AnonymousAccess注解
                    boolean methodAnnotated = entry.getValue().getMethod().isAnnotationPresent(AnonymousAccess.class);
                    // 检查类上是否有@AnonymousAccess注解
                    boolean classAnnotated = entry.getValue().getBeanType().isAnnotationPresent(AnonymousAccess.class);
                    return methodAnnotated || classAnnotated;
                }) .map(entry -> entry.getKey().getPatternsCondition().getPatterns())
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
//        //DisPatcherServlet-->HandlerMapping-->HandlerAdapter-->Controller
//        //前端控制器         -->请求处理器映射器 -->请求处理器适配器  -->请求处理器
//        //处理器映射器 保存的是 key(路径)和value(类名/方法名)的映射关系
//        //处理器适配器 处理入参和出参，并调用处理器方法
//        //SpringBoot 默认的 RequestMappingHandlerMapping 实现会扫描项目目录下的所有带有 @Controller 和 @RequestMapping 类进行处理.

    }

}